﻿using SimpleESBCore.Common;
using SimpleESBCore.Implement;
using SimpleESBCore.Implement.Datas;
using SimpleESBCore.Implement.Events;
using SimpleESBCore.Interfaces;
using SimpleESBServer.Handlers;
using SimpleESBServer.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SimpleESBServer
{
    public class EsbServer : IServer
    {
        GlobalClass GlobalClass = new GlobalClass();
        IMessageService messageService = new MessageService();
        ServerOption serverOption;
        ILog log;
        ISerialization serialization;
        SendHelper sh = new SendHelper();
        Thread threadHeart;//后台心跳线程
        Thread threadData;//后台数据线程
        public EsbServer(ServerOption serverOption, ILog log, ISerialization serialization)
        {
            this.serverOption = serverOption;
            this.log = log;
            this.serialization = serialization;
        }
        public void CreateTopic(string topicName)
        {
            if (!GlobalClass.EventLists.ContainsKey(topicName))
            {
                GlobalClass.EventLists.Add(topicName, new List<EventBase>());
            }
        }

        public void DeleteTopic(string topicName)
        {
            if (GlobalClass.EventLists.ContainsKey(topicName))
            {
                GlobalClass.EventLists.Remove(topicName);
            }
        }

        public void Distribution()
        {
            foreach (var topic in GlobalClass.EventLists)
            {
                foreach (var client in GlobalClass.TopicSockets[topic.Key])
                {
                    foreach (var message in topic.Value)
                    {
                        try
                        {
                            DataSendEvent dataSendEvent = new DataSendEvent();
                            dataSendEvent.EventData = message;
                            sh.SendData(client.ClientSocket, dataSendEvent, serialization);
                        }
                        catch(Exception ex)
                        {
                            log.LogInfo(new LogInfoData(ex.Message));
                        }
                    }
                }
            }
        }

        public bool IsExist(string topicName)
        {
            return GlobalClass.EventLists.ContainsKey(topicName);
        }

        public void Start()
        {
            //开启心跳服务
            if (GlobalClass.ServerHeartSocket == null)
            {
                GlobalClass.ServerHeartSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                EndPoint heartEndPoint = new IPEndPoint(serverOption.IPAddress, serverOption.HeartPort);
                GlobalClass.ServerHeartSocket.Bind(heartEndPoint);
                GlobalClass.ServerHeartSocket.Listen(10);
                log.LogInfo(new LogInfoData(string.Format("心跳服务在端口{0}开启成功!", serverOption.HeartPort)));
            }
            //开启数据服务
            if (GlobalClass.ServerDataSocket == null)
            {
                GlobalClass.ServerDataSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                EndPoint dataEndPoint = new IPEndPoint(serverOption.IPAddress, serverOption.DataPort);
                GlobalClass.ServerDataSocket.Bind(dataEndPoint);
                GlobalClass.ServerDataSocket.Listen(10);
                log.LogInfo(new LogInfoData(string.Format("数据服务在端口{0}开启成功!", serverOption.DataPort)));
            }

            //开始心跳接收连接
            threadHeart = new Thread(AcceptHeartConnect);
            threadHeart.Name = "HeartThread";
            threadHeart.IsBackground = true;
            threadHeart.Start();
            //开始数据接收连接
            threadData = new Thread(AcceptDataConnect);
            threadData.Name = "DataThread";
            threadData.IsBackground = true;
            threadData.Start();
            log.LogInfo(new LogInfoData("服务开启成功!"));
        }

        public void Stop()
        {
            //关闭所有的数据接收服务
            foreach (var item in GlobalClass.ClientInfos)
            {
                item.ClientSocket.Close();
            }
            GlobalClass.ClientInfos.Clear();
            //关闭所有的心跳接收服务
            foreach (var item in GlobalClass.ClientHeartInfos)
            {
                item.ClientSocket.Close();
            }
            GlobalClass.ClientHeartInfos.Clear();
            //关闭服务程序
            GlobalClass.ServerHeartSocket.Close();
            GlobalClass.ServerDataSocket.Close();
            GlobalClass.ServerHeartSocket = null;
            GlobalClass.ServerDataSocket = null;
            //关闭所有线程
            threadHeart.Abort();
            threadData.Abort();
            //执行一次垃圾回收
            GC.Collect();
        }
        /// <summary>
        /// 用于更新心跳连接
        /// </summary>
        private void AcceptHeartConnect()
        {
            while (true)
            {
                if (GlobalClass.ServerHeartSocket == null)
                {
                    Thread.Sleep(200);
                    continue;
                }
                try
                {
                    var client = GlobalClass.ServerHeartSocket.Accept();
                    string clientIp = client.RemoteEndPoint.ToString();
                    ClientHeartInfo clientHeartInfo = new ClientHeartInfo();
                    clientHeartInfo.ClientIP = client.RemoteEndPoint.ToString();
                    clientHeartInfo.NextHeartTime = DateTime.Now.AddSeconds(30);
                    clientHeartInfo.ClientSocket = client;
                    GlobalClass.ClientHeartInfos.Add(clientHeartInfo);
                    //开始接收心跳
                    ReceiveHeart(clientHeartInfo);
                }
                catch (Exception)
                {
                    //log.LogInfo(new LogInfoData(ex.Message, LogType.Exception));
                }
                Thread.Sleep(200);
            }
        }
        /// <summary>
        /// 用于更新数据连接
        /// </summary>
        private void AcceptDataConnect()
        {
            while (true)
            {
                if (GlobalClass.ServerDataSocket == null)
                {
                    Thread.Sleep(200);
                    continue;
                }
                try
                {
                    var client = GlobalClass.ServerDataSocket.Accept();
                    string clientIp = client.RemoteEndPoint.ToString();
                    ClientInfo clientInfo = new ClientInfo();
                    clientInfo.ClientStatus = ClientStatus.Connected;
                    clientInfo.ClientSocket = client;
                    GlobalClass.ClientInfos.Add(clientInfo);
                    //开始接收数据
                    ReceiveData(clientInfo);
                }
                catch (Exception)
                {
                    //log.LogInfo(new LogInfoData(ex.Message, LogType.Exception));
                }
                Thread.Sleep(200);
            }
        }
        /// <summary>
        /// 接收并处理心跳数据
        /// </summary>
        /// <param name="socket"></param>
        private void ReceiveHeart(ClientHeartInfo clientHeartInfo)
        {
            Task.Run(() =>
            {
                byte[] buffer = new byte[136];//实例化一个接收数据的缓冲区
                while (clientHeartInfo.ClientSocket.Connected)
                {
                    try
                    {
                        Array.Clear(buffer, 0, 136);
                        clientHeartInfo.ClientSocket.Receive(buffer);//接收数据并存放到缓冲区内
                        string str = Encoding.Unicode.GetString(buffer, 0, 136);//将信息转换成数据
                        HeartEvent eventBase = serialization.DeSerializer<HeartEvent>(str);
                        IHandler<HeartEvent> handler = new HeartPingHandler();
                        handler.Handler(eventBase);//处理此事件

                        //心跳事件需要更新心跳状态
                        if (clientHeartInfo.NextHeartTime < DateTime.Now)
                        {
                            GlobalClass.ClientHeartInfos.Remove(clientHeartInfo);
                            clientHeartInfo.ClientSocket.Close();
                            clientHeartInfo.ClientSocket = null;
                            log.LogInfo(new LogInfoData(string.Format("客户端{0}失去了连接!", clientHeartInfo.ClientIP)));
                            break;
                        }
                        else
                        {
                            HeartEvent result = new HeartEvent();
                            result.EventData = "pong";
                            string message = serialization.Serializer(result);
                            byte[] bufferResult = Encoding.Unicode.GetBytes(message);
                            clientHeartInfo.ClientSocket.Send(bufferResult);
                            clientHeartInfo.NextHeartTime = DateTime.Now.AddSeconds(30);
                        }
                    }
                    catch (Exception ex)
                    {
                        continue;
                    }
                    Task.Delay(50);
                }
            });
        }
        private void ReceiveData(ClientInfo clientInfo)
        {
            Task.Run(() =>
            {
                bool receiveLength = false;
                //此处用两个不同的缓冲区，是为了解决Tcp沾包的问题
                byte[] bufferLength = new byte[184];//实例化一个接收数据长度信息的缓冲区
                byte[] bufferSource = null;//实例化一个接收数据原始信息的缓冲区
                while (clientInfo.ClientSocket.Connected)
                {
                    try
                    {
                        if (!receiveLength)
                        {
                            Array.Clear(bufferLength, 0, bufferLength.Length);
                            clientInfo.ClientSocket.Receive(bufferLength);//接收数据并存放到缓冲区内
                            string str = Encoding.Unicode.GetString(bufferLength, 0, 184);//将信息转换成数据
                            DataSendEvent dataSendEvent = serialization.DeSerializer<DataSendEvent>(str);

                            receiveLength = true;
                            var source = dataSendEvent.EventData as DataConfigData;
                            bufferSource = new byte[Convert.ToInt32(source.DataLength)];
                            continue;
                        }
                        else
                        {
                            receiveLength = false;
                            Array.Clear(bufferSource, 0, bufferSource.Length);
                            clientInfo.ClientSocket.Receive(bufferSource);//接收数据并存放到缓冲区内
                            string str = Encoding.Unicode.GetString(bufferLength, 0, bufferSource.Length);//将信息转换成数据
                            EventBase dataEvent = serialization.DeSerializer<EventBase>(str);
                            IHandler<EventBase> handler = new DataReceiveHandler(GlobalClass, clientInfo.ClientSocket, serialization);
                            handler.Handler(dataEvent);
                        }
                    }
                    catch (Exception ex)
                    {
                        ErrorEvent error = new ErrorEvent();
                        ErrorData data = new ErrorData();
                        data.ErrorMessage = ex.Message;
                        error.EventData = data;
                        sh.SendData(clientInfo.ClientSocket, error, serialization);
                    }
                    Task.Delay(50);
                }
            });
        }
    }
}
